home *** CD-ROM | disk | FTP | other *** search
Text File | 1987-11-05 | 11.8 KB | 461 lines | [TEXT/MPS ] |
- ;
- ; fractal xcmd v0.3 -- Doug Felt, Oct 14, 1987
- ;
- ; This draws a fractal on the screen. Not to the card, yet. Function is
- ; f(z) = z * z + c, julia set mapped to 4 patterns.
- ;
- ; Format:
- ; Fractal seed.h seed.v [res = 8 [limit = 32 [lock = 0]]]
- ;
- ; seed is the complex constant c (v imaginary)
- ; res is the number of pixels on a side for the point to plot
- ; limit is the max number of iterations (best between 16 & 128, multiple of 4),
- ; lower limit means most complex regions of the fractal are white
- ; if lock is 0, pressing the mouse will immediately stop the drawing, otherwise
- ; pressing the mouse has no effect and drawing can only be stopped by reboot or
- ; fancy macsbug work.
- ;
- ; Doug Felt, AIR/CAT Project
- ; duggie@jessica.stanford.edu
- ;
- ;
- ; To compile and link in MPW C:
- ;
- ; C -q2 Fractal.c
- ; link -sn Main=Fractal -sn STDIO=Fractal ∂
- ; -sn INTENV=Fractal -rt XCMD=104 ∂
- ; -m FRACTAL Fractal.c.o "{CLibraries}CRunTime.o" ∂
- ; -o HyperCommands
- ;
- ;
- ; Well now, I thought this was so neat, and Doug was right it needs a
- ; little more speed. So thats what I did, I rewrote the "C" program in
- ; assembler with direct processing on the MC68881 FPU. I think this makes
- ; quite a difference. The only thing is that it only runs on a MacII. It
- ; might run on one or more of the accelerator cards. Give it a try. If
- ; necessary, change the COID= parameter below if they are using other than 1.
- ;
- ; Ray Sanders
- ; Green Grass Software, Inc.
- ;
- ; CIS: 70277,3233 GEnie: RAYSANDERS
- ;
- ; To assemble and link with MPW:
- ;
- ; fractal2.a.o ƒ fractal2.make fractal2.a
- ; Asm fractal2.a -l -font Monaco,9
- ; fractal2 ƒ fractal2.make fractal2.a.o
- ; link -o fractal2 -rt XCMD=105 -sn Main=Fractal2 -t STAK -c WILD ∂
- ; fractal2.a.o ∂
- ; -o "Fractals"
- ;
- ;
- fractal2 MAIN
-
- BLANKS ON
- STRING ASIS
- MC68881 COID=1,PREC=X,ROUND=N
- ; INCLUDE 'Traps.a'
- ; INCLUDE 'SysEqu.a'
- PRINT OFF
- INCLUDE 'Traps.a'
- INCLUDE 'SysEqu.a'
- PRINT ON,NOWARN
- ; PRINT ON
-
-
- ; HyperCard data structure offsets
-
- XCmdParamCount EQU 0 ;number of parameters
- XCmdParams EQU 2 ;16 handles to C-strings
- XCmdReturnVal EQU 66 ;handle to return string
- XCmdPassFlag EQU 70 ;boolean, to pass message through
- XCmdEntryPoint EQU 72 ;hyperCard call-back
- XCmdRequest EQU 76 ;call back opcode field
- XCmdResult EQU 78 ;call back result field
- XCmdInArgs EQU 80 ;8 longs, input arguments
- XCmdOutArgs EQU 112 ;4 longs, output arguments
-
- MenuList EQU $A1C
-
- ; result codes
-
- xresSucc EQU 0
- xresFail EQU 1
- xresNotImp EQU 2
-
- ; request codes
-
- xreqSendCardMessage EQU 1
- xreqEvalExpr EQU 2
- xreqStringLength EQU 3
- xreqStringMatch EQU 4
- xreqSendHCMessage EQU 5
- xreqZeroBytes EQU 6
- xreqPasToZero EQU 7
- xreqZeroToPas EQU 8
- xreqStrToLong EQU 9
- xreqStrToNum EQU 10
- xreqStrToBool EQU 11
- xreqStrToExt EQU 12
- xreqLongToStr EQU 13
- xreqNumToStr EQU 14
- xreqNumToHex EQU 15
- xreqBoolToStr EQU 16
- xreqExtToStr EQU 17
- xreqGetGlobal EQU 18
- xreqSetGlobal EQU 19
- xreqGetFieldByName EQU 20
- xreqGetFieldByNum EQU 21
- xreqGetFieldByID EQU 22
- xreqSetFieldByName EQU 23
- xreqSetFieldByNum EQU 24
- xreqSetFieldByID EQU 25
- xreqStringEqual EQU 26
- xreqReturnToPas EQU 27
- xreqScanToReturn EQU 28
- xreqScanToZero EQU 39 ; was suppose to be 29! Oops!
-
-
- ; definition of stack frame
-
- stackStor RECORD 0,DECREMENT
- stackStorStart EQU *
- xcmdBlockAddr DS.L 1
- noLock DS.W 1
- res DS.W 1
- hsize DS.W 1
- vsize DS.W 1
- i DS.W 1
- j DS.W 1
- iter DS.W 1
- limit DS.W 1
- rbaseh DS.W 1
- rat DS.L 3
- seedh DS.L 3
- seedv DS.L 3
- valh DS.L 3
- valv DS.L 3
- temp DS.L 3
- basev DS.L 3
- baseh DS.L 3
- hsq DS.L 3
- vsq DS.L 3
- real2 DS.L 3
- realn2 DS.L 3
- real100 DS.L 3
- fake256 DS.L 1
- fake171 DS.L 1
- fake2 DS.L 1
- fake100 DS.L 1
- r DS.W 4
- pats DS.L 8
- tempX DS.L 3
- tempStr DS.B 256
- tempL DS.L 1
- stackStorLen EQU *-stackStorStart
- ENDR
-
- WITH stackStor
- EntryPoint
- ;;; _Debugger ;
- LINK A6,#stackStorLen ;
- MOVEM.L A0-A6/D0-D7,-(SP) ;
-
- MOVE.L 8(A6),A3 ;
- MOVE.L A3,xcmdBlockAddr(A6) ;
-
- CMPI.W #3,XCmdParamCount(A3) ; if (paramPtr->paramCount<2) return
- BLT FracsDone ;
-
- MOVE.L #$00000000,pats(A6) ; pats[0].long1 = 0
- MOVE.L #$00000000,pats+4(A6) ; pats[0].long2 = 0
- MOVE.L #$AA005500,pats+8(A6) ; pats[1].long1 = 0xaa005500
- MOVE.L #$AA005500,pats+12(A6) ; pats[1].long2 = 0xaa005500
- MOVE.L #$55FFAAFF,pats+16(A6) ; pats[2].long1 = 0x55ffaaff
- MOVE.L #$55FFAAFF,pats+20(A6) ; pats[2].long2 = 0x55ffaaff
- MOVE.L #$FFFFFFFF,pats+24(A6) ; pats[3].long1 = 0xffffffff
- MOVE.L #$FFFFFFFF,pats+28(A6) ; pats[3].long2 = 0xffffffff
-
- MOVE.W #8,res(A6) ; res = 8
-
- MOVE.W #32,limit(A6) ; limit = 32
-
- MOVE.W #1,nolock(A6) ; nolock = 1
-
- MOVE.L XCmdParams(A3),-(SP) ; seedh = ParamToExt(paramPtr,0)
- PEA.L seedh(A6) ;
- BSR ZeroToExt ;
- ADDQ.L #8,SP ;
-
- MOVE.L XCmdParams+4(A3),-(SP) ; seedv = ParamToExt(paramPtr,1)
- PEA.L seedv(A6) ;
- BSR ZeroToExt ;
- ADDQ.L #8,SP ;
-
- CMPI.W #3,XCmdParamCount(A3) ; if (paramPtr->paramCount>2)
- BLT @150 ;
- MOVE.L XCmdParams+8(A3),-(SP) ; res = ParamToNum(paramPtr,2)
- PEA.L tempL(A6) ;
- BSR ZeroToNum ;
- ADDQ.L #8,SP ;
- MOVE.W tempL+2(A6),res(A6) ;
-
- CMPI.W #0,res(A6) ; if (res <= 0)
- BGT.S @110 ;
- MOVE.W #1,res(A6) ; res = 1
- @110
-
- CMPI.W #4,XCmdParamCount(A3) ; if (paramPtr->paramCount>3)
- BLT @150 ;
- MOVE.L XCmdParams+12(A3),-(SP) ; limit = ParamToNum(paramPtr,3)
- PEA.L tempL(A6) ;
- BSR ZeroToNum ;
- ADDQ.L #8,SP ;
- MOVE.W tempL+2(A6),limit(A6) ;
-
- CMPI.W #3,limit(A6) ; if (limit<4)
- BGT.S @120 ;
- MOVE.W #4,limit(A6) ; limit = 4
- @120
-
- CMPI.W #5,XCmdParamCount(A3) ; if (paramPtr->paramCount>4)
- BLT @150 ;
- MOVE.L XCmdParams+16(A3),-(SP) ; nolock = !ParamToNum(paramPtr,4)
- PEA.L tempL(A6) ;
- BSR ZeroToNum ;
- ADDQ.L #8,SP ;
- MOVE.W tempL+2(A6),nolock(A6) ;
- NOT.W nolock(A6) ;
- @150
-
- ; /* map screen onto -2 to 2 range */
- ;
- ; /* 0,0 is at 512/2, 342/2 = 256,171 */
- ;
- ; /* gridding to res requires that I find out how many boxes wide and tall
- ; the image is, and map each box onto a value in r2. then i iterate over
- ; all the boxes calling the function until the x or y exceeds some limit.
- ; then i map the number of iterations into a 'color' */
- ;
- ; /* since we don't have a global data area for extended constants to live in,
- ; use longs and fake the compiler into making the correct SANE calls to
- ; build the extended values. Is there a better way (besides using Pascal!) */
- ;
- MOVE.L #256,fake256(A6) ; fake256 = 256
-
- MOVE.L #171,fake171(A6) ; fake171 = 171
-
- MOVE.L #2,fake2(A6) ; fake2 = 2
-
- MOVE.L #100,fake100(A6) ; fake100 = 100
-
- MOVE.L #256,D0 ; hsize = (fake256/res)+1
- DIVS.W res(A6),D0 ;
- ADDQ.W #1,D0 ;
- MOVE.W D0,hsize(A6) ;
-
- MOVE.L #171,D0 ; vsize = (fake171/res)+1
- DIVS.W res(A6),D0 ;
- ADDQ.W #1,D0 ;
- MOVE.W D0,vsize(A6) ;
-
- FMOVECR.X #$34,FP0 ; real100 = fake100
- FMOVE.X FP0,real100(A6) ;
-
- FMOVE.W #2,FP0 ; real2 = fake2
- FMOVE.X FP0,real2(A6) ;
-
- FMOVE.W #-2,FP0 ; realn2 = -fake2
- FMOVE.X FP0,realn2(A6) ;
-
- FMOVE.X real2(A6),FP0 ; rat = real2/hsize
- FDIV.W hsize(A6),FP0 ;
- FMOVE.X FP0,rat(A6) ; /* reals intermediate result because of real2 */
-
- MOVE.W res(A6),D0 ; rbaseh = 256-hsize*res
- MULS.W hsize(A6),D0 ;
- MOVE.W #256,D1 ;
- SUB.W D0,D1 ;
- MOVE.W D1,rbaseh(A6) ;
-
- MOVE.W res(A6),D0 ; r.top = 171-vsize*res
- MULS.W vsize(A6),D0 ;
- MOVE.W #171,D1 ;
- SUB.W D0,D1 ;
- MOVE.W D1,r(A6) ;
-
- ADD.W res(A6),D1 ; r.bottom = r.top + res
- MOVE.W D1,r+4(A6) ;
-
- FMOVE.L fake171(A6),FP2 ; basev = realn2*fake171/fake256
- FMUL.X realn2(A6),FP2 ; /* center it */
- FDIV.L fake256(A6),FP2 ;
-
- FMOVE.X seedv(A6),FP0 ;
- FMOVE.X seedh(A6),FP1 ;
-
- ; for loop
-
- MOVE.W vsize(A6),D4 ; for (i=-vsize; i<vsize; ++i)
- NEG.W D4 ;
- @200
- CMP.W vsize(A6),D4 ;
- BGE @500 ;
-
- MOVE.W rbaseh(A6),D0 ; r.left = rbaseh
- MOVE.W D0,r+2(A6) ;
-
- ADD.W res(A6),D0 ; r.right = r.left + res
- MOVE.W D0,r+6(A6) ;
-
- FMOVE.X realn2(A6),FP3 ; baseh = realn2
-
- ; for loop
-
- MOVE.W hsize(A6),D3 ; for (j=-hsize; j<hsize; ++j)
- NEG.W D3 ;
- @250
- CMP.W hsize(A6),D3 ;
- BGE @450 ;
-
- FMOVE.X FP3,FP5 ; valh = baseh
-
- FMOVE.X FP2,FP4 ; valv = basev
-
- CLR.W D5 ; iter = 0
-
- ; do loop
-
- @300
- ;
- ;
- ; register assignments to speed up loop
- ;
- ; hsq is in FP7
- ; vsq is in FP6
- ; valh is in FP5
- ; valv is in FP4
- ; baseh is in FP3
- ; basev is in FP2
- ; seedh is in FP1
- ; seedv is in FP0
- ;
-
- FMOVE.X FP4,FP6 ; vsq = valv * valv
- FMUL.X FP4,FP6 ;
-
- FMUL.X FP5,FP4 ; valv = real2*valh*valv + seedv
- FADD.X FP4,FP4 ;
- FADD.X FP0,FP4 ;
-
- FMUL.X FP5,FP5 ; hsq = valh * valh
- FMOVE.X FP5,FP7 ;
-
- FSUB.X FP6,FP5 ; valh = hsq - vsq + seedh
- FADD.X FP1,FP5 ;
-
- ADDQ.W #1,D5 ; ++iter
-
- FADD.X FP6,FP7 ; while ((hsq+vsq<real100) && (iter<limit))
- FMOVECR.X #$34,FP6 ;
- FCMP.X FP7,FP6 ;
- FBLE.W @350 ;
- CMP.W limit(A6),D5 ;
- BLE @300 ;
-
- @350
- FADD.X rat(A6),FP3 ; baseh += rat
-
- ANDI.W #3,D5 ; PenPat(&pats[iter & 0x03])
- LSL.W #3,D5 ;
- LEA.L pats(A6),A0 ;
- ADDA.W D5,A0 ;
- MOVE.L A0,-(SP) ;
- _PenPat ;
-
- PEA.L r(A6) ; PaintRect(&r)
- _PaintRect ;
-
- MOVE.W res(A6),D0 ; r.left += res
- ADD.W D0,r+2(A6) ;
-
- ADD.W D0,r+6(A6) ; r.right += res
-
- ADDQ.W #1,D3 ;
- BRA @250 ;
-
- @450
-
- FADD.X rat(A6),FP2 ; basev += rat
-
- MOVE.W res(A6),D0 ; r.top += res
- ADD.W D0,r(A6) ;
-
- ADD.W D0,r+4(A6) ; r.bottom += res
-
- TST.W nolock(A6) ; if (nolock && Button()) return
- BEQ.S @475 ;
- CLR.W -(SP) ;
- _Button ;
- TST.W (SP)+ ;
- BNE FracsDone ;
- @475
-
- ADDQ.W #1,D4 ;
- BRA @200 ;
-
- @500
- FracsDone
- MOVEM.L (SP)+,A0-A6/D0-D7 ; restore registers
- UNLK A6
- MOVE.L (SP)+,(SP)
- RTS
-
- ZeroToNum
- MOVE.L xcmdBlockAddr(A6),A3 ; xcmd blk ptr
- MOVE.L 8(SP),A0 ; handle to num string
- MOVE.L (A0),XCmdInArgs(A3) ; ptr to num string
- LEA.L tempStr(A6),A0 ; pt to temp string area
- MOVE.L A0,XCmdInArgs+4(A3) ; set temp string ptr
- MOVE.W #xreqZeroToPas,XCmdRequest(A3) ; convert to pascal string
- MOVE.L XCmdEntryPoint(A3),A0 ; get entry point addr
- JSR (A0) ; call HC
- LEA.L tempStr(A6),A0 ; pt to temp string area
- MOVE.L A0,XCmdInArgs(A3) ; set first arg
- MOVE.W #xreqStrToNum,XCmdRequest(A3) ; set req code
- MOVE.L XCmdEntryPoint(A3),A0 ; get entry point addr
- JSR (A0) ; call HC
- MOVE.L 4(SP),A0 ; ptr to result field
- MOVE.L XCmdOutArgs(A3),(A0) ; set result
- RTS ;
-
- ZeroToExt
- MOVE.L xcmdBlockAddr(A6),A3 ; xcmd blk ptr
- MOVE.L 8(SP),A0 ; handle to num string
- MOVE.L (A0),XCmdInArgs(A3) ; ptr to num string
- LEA.L tempStr(A6),A0 ; pt to temp string area
- MOVE.L A0,XCmdInArgs+4(A3) ; set temp string ptr
- MOVE.W #xreqZeroToPas,XCmdRequest(A3) ; convert to pascal string
- MOVE.L XCmdEntryPoint(A3),A0 ; get entry point addr
- JSR (A0) ; call HC
- LEA.L tempStr(A6),A0 ; pt to temp string area
- MOVE.L A0,XCmdInArgs(A3) ; set first arg
- LEA.L tempX(A6),A0 ; pt to temp string area
- MOVE.L A0,XCmdInArgs+4(A3) ; set first arg
- MOVE.W #xreqStrToExt,XCmdRequest(A3) ; set req code
- MOVE.L XCmdEntryPoint(A3),A0 ; get entry point addr
- JSR (A0) ; call HC
- MOVE.L 4(SP),A0 ; ptr to result field
- MOVE.W tempX(A6),(A0)+ ; set result
- CLR.W (A0)+ ; fill in the zeros
- MOVE.L tempX+2(A6),(A0)+ ; set result
- MOVE.L tempX+6(A6),(A0)+ ; set result
- RTS ;
-
-
- ENDWITH
- ENDMAIN
- END
-
-